package query_service

import (
	"context"
	"gitee.com/zylvcxq/gotham-utils/log_util"
	"gitee.com/zylvcxq/gotham-utils/mail"
	"github.com/go-kratos/kratos/v2/log"
	"gotham-plan-manage/internal/app/convertor"
	"gotham-plan-manage/internal/domain/model/plan-aggregate/aggregate"
	entity2 "gotham-plan-manage/internal/domain/model/plan-aggregate/entity"
	"gotham-plan-manage/internal/domain/query"
	"gotham-plan-manage/internal/domain/repo"
	"gotham-plan-manage/internal/infra/cache/redis"
	"gotham-plan-manage/internal/infra/cache/redis/plan"
	"gotham-plan-manage/internal/infra/cache/redis/task"
	"gotham-plan-manage/internal/interfaces/response"
	"gotham-plan-manage/pkg/consts"
	"gotham-plan-manage/pkg/dateutils"
	"gotham-plan-manage/pkg/jwt_util"
	"sync"
	"time"
)

/*
   @author：zhongyang
   @date:2023/4/2
   @description: 计划管理-查询应用服务（查询）
*/

type PlanManageQueryService struct {
	PlanManageRepo repo.PlanManageIRepo
	planConvertor  convertor.PlanManageConvertor
	logger         *log_util.GothamLogger
}

func NewPlanManageQueryService(planManageRepo repo.PlanManageIRepo, logger log.Logger) *PlanManageQueryService {
	return &PlanManageQueryService{PlanManageRepo: planManageRepo, logger: log_util.NewGothamLogger(logger, mail.NewRealMailSender(redis.GetConn()))}
}

func (s *PlanManageQueryService) GeneratePlanReport(context context.Context, query *query.GeneratePlanReportQuery) (*response.PlanReportResponse, error) {
	// 拿到完整的计划聚合根
	plan, err := s.PlanManageRepo.FindCompletePlanById(context, query.PlanId)
	if err != nil {
		return nil, err
	}
	// 在聚合根里面生成报告，并返回。
	err = plan.GenerateReport()
	if err != nil {
		return nil, err
	}
	// 转换回DTO，并返回
	return s.planConvertor.ConvertPlanReportResponse(plan), nil
}

func (s *PlanManageQueryService) FindPlan(context context.Context, query *query.GetPlanQuery) (*response.PlanResponse, error) {
	plan, err := s.PlanManageRepo.FindPlanById(context, query.PlanId)
	if err != nil {
		return nil, err
	}
	// 将聚合根转换成DTO并返回
	return s.planConvertor.ConvertPlanResponse(plan), nil
}

func (s *PlanManageQueryService) FindPlanDetail(context context.Context, detailQuery *query.GetPlanDetailQuery) (*response.PlanDetailResponse, error) {
	plan, err := s.PlanManageRepo.FindPlanContainsDetailById(context, detailQuery.PlanId)
	if err != nil {
		return nil, err
	}
	return s.planConvertor.ConvertPlanDetailResponse(plan), nil
}

func (s *PlanManageQueryService) FindPlanMultiLevelList(ctx context.Context, listQuery *query.GetPlanListQuery) ([]*response.PlanPageResponse, int64, error) {
	parentPlans, total, err := s.PlanManageRepo.FindParentPlanListPage(ctx, listQuery.Page, listQuery.PageSize, jwt_util.GetUserId(ctx))
	if err != nil {
		return nil, 0, err
	}
	var wg sync.WaitGroup
	for _, planAgr := range parentPlans {
		wg.Add(1)
		go func(item *aggregate.PlanAggregate) {
			defer wg.Done()
			todoTotal, err := s.PlanManageRepo.GetTaskTotalByPlanId(ctx, item.PlanId, consts.FinishedBool)
			if err != nil {
				s.logger.Errorf(ctx, "查询total异常 err:%v", err)
			}
			item.CalTaskTotal(todoTotal)
			childrenPlan, err := s.getChildrenPlan(ctx, item.PlanId, jwt_util.GetUserId(ctx))
			if err != nil {
				s.logger.Errorf(ctx, "查询childrenRes异常 err:%v", err)
			}
			item.AddChildrenPlan(childrenPlan)
		}(planAgr)
		planAgr.CalPlanStatus()
		planAgr.CalSurplusTime()
	}
	wg.Wait()
	res := s.planConvertor.ConvertPlanPageResponse(parentPlans)
	return res, total, nil
}

func (s *PlanManageQueryService) FindPlanReport(ctx context.Context, reportQuery *query.FindPlanReportQuery) (*response.PlanReportResponse, error) {
	plan, err := s.PlanManageRepo.FindPlanContainsReportById(ctx, reportQuery.PlanId)
	if err != nil {
		s.logger.Errorf(ctx, "PlanManageQueryService.FindPlanReport err:%v", err)
		return nil, err
	}
	return s.planConvertor.ConvertPlanReportResponse(plan), err
}

func (s *PlanManageQueryService) getChildrenPlan(ctx context.Context, parentId, userID string) ([]*aggregate.PlanAggregate, error) {
	var wg sync.WaitGroup
	children, err := s.PlanManageRepo.FindChildrenPlanListByParentId(ctx, parentId, userID)
	if err != nil {
		return nil, err
	}
	for _, child := range children {
		wg.Add(1)
		go func(plan *aggregate.PlanAggregate) {
			defer wg.Done()
			total, err := s.PlanManageRepo.GetTaskTotalByPlanId(ctx, plan.PlanId, consts.FinishedBool)
			if err != nil {
				s.logger.Errorf(ctx, "查询total异常 err:%v", err)
				return
			}
			plan.CalTaskTotal(total)
		}(child)
		child.CalPlanStatus()
		child.CalSurplusTime()
	}
	wg.Wait()
	return children, nil
}

func (s *PlanManageQueryService) GetTaskItemById(context context.Context, itemQuery *query.GetTaskItemQuery) (*response.TaskItemResponse, error) {
	plan, err := s.PlanManageRepo.GetTaskItemById(context, itemQuery.TaskItemId)
	if err != nil {
		return nil, err
	}
	return s.planConvertor.ConvertTaskItem(plan), nil
}

func (s *PlanManageQueryService) GetTaskList(context context.Context, listQuery *query.GetTaskListQuery) ([]*response.TaskListResponse, int64, error) {
	plan, total, err := s.PlanManageRepo.GetTaskList(context, listQuery.PlanId, listQuery.Page, listQuery.PageSize)
	if err != nil {
		return nil, 0, err
	}
	return s.planConvertor.ConvertTaskList(plan), total, nil
}

func (s *PlanManageQueryService) FindOneDayQuestions(context context.Context, questionQuery *query.FindOneDayQuestionQuery) ([]*response.QuestionResponse, error) {
	plan, err := s.PlanManageRepo.FindOneDayQuestions(context, questionQuery.PlanId, questionQuery.TodoTaskDate)
	if err != nil {
		return nil, err
	}
	return s.planConvertor.ConvertQuestions(plan), nil
}

func (s *PlanManageQueryService) SearchQuestions(context context.Context, questionQuery *query.SearchQuestionQuery) ([]*response.QuestionResponse, error) {
	plan, err := s.PlanManageRepo.SearchQuestions(context, questionQuery.PlanId, questionQuery.Content)
	if err != nil {
		return nil, err
	}
	return s.planConvertor.ConvertQuestions(plan), nil
}

// todo 这里代码放到repo去
func (s *PlanManageQueryService) GetOngoingTasks(context context.Context, tasksQuery *query.GetOngoingTasksQuery) ([]*response.TaskItemResponse, error) {
	// 获取进行中的计划
	planIds, err := s.PlanManageRepo.FindOngoingPlanIds(context, jwt_util.GetUserId(context))
	if err != nil {
		return nil, err
	}
	// 获取对应待办
	tasks, err := s.PlanManageRepo.GetOngoingTasksByPlanIds(context, planIds, tasksQuery.Scope)
	var res []*response.TaskItemResponse
	var wg sync.WaitGroup
	var mu sync.Mutex
	// 再获取所有待办项
	for _, task := range tasks {
		wg.Add(1)
		go func(taskReq *entity2.Task) {
			defer wg.Done()
			taskItems, err := s.PlanManageRepo.FindOngoingTaskItems(context, taskReq.TaskId)
			if err != nil {
				return
			}
			mu.Lock()
			for _, item := range taskItems {
				itemRes := &response.TaskItemResponse{
					TaskItemId: item.Id,
					Content:    item.Content,
					TodoTaskId: taskReq.TaskId,
					Level:      item.Level,
					PlanId:     taskReq.PlanId,
					FinishDate: item.FinishDate,
				}
				res = append(res, itemRes)
			}
			mu.Unlock()
		}(task)
	}
	wg.Wait()
	return res, nil
}

func (s *PlanManageQueryService) IsFinishTask(context context.Context, taskQuery *query.IsFinishTaskQuery) (bool, error) {
	return s.PlanManageRepo.IsFinishTask(context, taskQuery.PlanID)
}

func (s *PlanManageQueryService) GetAllPlan(context context.Context, userID string) ([]*response.PlanResponse, error) {
	// 根据用户id查询所有计划
	plans, err := s.PlanManageRepo.FindAllPlanByUserId(context, userID)
	if err != nil {
		return nil, err
	}
	var res []*response.PlanResponse
	for _, plan := range plans {
		res = append(res, s.planConvertor.ConvertPlanResponse(plan))
	}
	return res, nil
}

func (s *PlanManageQueryService) CompletionRateAnalysis(ctx context.Context, analysisQuery *query.CompletionRateAnalysisQuery) ([]*response.CompletionRateAnalysisResponse, error) {
	// 按近到远顺序查出所有的日期
	plan, err := s.PlanManageRepo.FindAllTaskByPlanId(ctx, analysisQuery.PlanID)
	if err != nil {
		return nil, err
	}
	var wg sync.WaitGroup
	var mu sync.Mutex
	resMap := make(map[string]*response.CompletionRateAnalysisResponse)
	res := initCompletionRateAnalysisResponse(plan.Tasks[len(plan.Tasks)-1].ExecuteDate, time.Now().Format(time.DateOnly))
	// 分别查出所有的已完成和未完成数，并发跑
	for _, task := range plan.Tasks {
		wg.Add(1)
		task1 := task
		go func() {
			defer wg.Done()
			taskItems, err := s.PlanManageRepo.GetTaskItemByTaskId(ctx, task1.TaskId)
			if err != nil {
				s.logger.Errorf(ctx, "PlanManageQueryService.CompletionRateAnalysis err:%v", err)
				return
			}
			// 计算已完成多少个，未完成多少个
			completeNum, unCompleteNum := analysisCompleteRate(taskItems)
			itemRes := &response.CompletionRateAnalysisResponse{
				TodoTaskDate:   task1.ExecuteDate,
				CompletedNum:   completeNum,
				UnCompletedNum: unCompleteNum,
			}
			mu.Lock()
			resMap[itemRes.TodoTaskDate] = itemRes
			mu.Unlock()
		}()
	}
	wg.Wait()
	for i, item := range res {
		if _, ok := resMap[item.TodoTaskDate]; ok {
			res[i] = resMap[item.TodoTaskDate]
		}
	}
	return res, nil
}

func initCompletionRateAnalysisResponse(startDate string, endDate string) []*response.CompletionRateAnalysisResponse {
	startTime, _ := time.Parse(time.DateOnly, startDate)
	endTime, _ := time.Parse(time.DateOnly, endDate)

	var responses []*response.CompletionRateAnalysisResponse
	for currentTime := startTime; currentTime.Before(endTime.AddDate(0, 0, 1)); currentTime = currentTime.AddDate(0, 0, 1) {
		res := &response.CompletionRateAnalysisResponse{
			TodoTaskDate:   currentTime.Format(time.DateOnly),
			CompletedNum:   0,
			UnCompletedNum: 0,
		}
		responses = append(responses, res)
	}
	return responses
}

func (s *PlanManageQueryService) GetOngoingPlan(ctx context.Context) (*response.PlanResponse, error) {
	plan, err := s.PlanManageRepo.GetOngoingPlanByUserId(ctx, jwt_util.GetUserId(ctx))
	if err != nil {
		return nil, err
	}
	return s.planConvertor.ConvertPlanResponse(plan), nil
}

func (s *PlanManageQueryService) WeeklyDistributionAnalysis(ctx context.Context, analysisQuery *query.WeeklyDistributionAnalysisQuery) ([]*response.WeeklyDistributionAnalysisResponse, error) {
	// 先把该计划所有待办都查出来，然后进行统计
	plan, err := s.PlanManageRepo.FindAllTaskByPlanId(ctx, analysisQuery.PlanID)
	if err != nil {
		return nil, err
	}
	resMap := make(map[string]int32)
	for _, task := range plan.Tasks {
		count, err := s.PlanManageRepo.GetTaskItemTotalByTaskId(ctx, task.TaskId)
		if err != nil {
			return nil, err
		}
		weekday, _ := dateutils.GetWeekday(task.ExecuteDate)
		// 判断是星期几
		resMap[weekday] += int32(count)
	}
	var res []*response.WeeklyDistributionAnalysisResponse
	for weekday, value := range resMap {
		item := &response.WeeklyDistributionAnalysisResponse{
			WeekName: weekday,
			Value:    value,
		}
		res = append(res, item)
	}
	return res, nil
}

func (s *PlanManageQueryService) ReviewAnalysis(ctx context.Context, analysisQuery *query.ReviewAnalysisQuery) (*response.ReviewAnalysisResponse, error) {
	// 获取本周时间段的待办完成数
	startDate, endDate := dateutils.WeekIntervalTime(0)
	thisWeekTotal, err := s.PlanManageRepo.GetFinishTaskItemTotalByDateRange(ctx, analysisQuery.PlanID, startDate, endDate)
	if err != nil {
		return nil, err
	}
	// 获取上周时间段的待办完成数
	lastStartDate, lastEndDate := dateutils.WeekIntervalTime(-1)
	lastWeekTotal, err := s.PlanManageRepo.GetFinishTaskItemTotalByDateRange(ctx, analysisQuery.PlanID, lastStartDate, lastEndDate)
	if err != nil {
		return nil, err
	}
	// 获取设定的完成目标数
	targetTaskItemTotal := task.GetThisWeekTargetTaskItemTotal(ctx, plan.GeneratePlanReviewKey(analysisQuery.PlanID, startDate, endDate))
	return &response.ReviewAnalysisResponse{
		LastWeekFinishTotal:       lastWeekTotal,
		FinishTotal:               thisWeekTotal,
		NextWeekTargetFinishTotal: targetTaskItemTotal,
	}, nil
}

// 统计待办项完成数和未完成数
func analysisCompleteRate(taskItems []*entity2.TaskItem) (int32, int32) {
	completeNum, unCompleteNum := 0, 0
	for _, item := range taskItems {
		if item.FinishDate == consts.DefaultDate {
			unCompleteNum++
		} else {
			completeNum++
		}
	}
	return int32(completeNum), int32(unCompleteNum)
}
